#!/bin/bash
#
# Initialize SRIOV virtual devices
#
# This is usually run automatically by systemd after a hardware activation
# event in udev has triggered a start of the rdma.service unit
port=1

function __get_parent_pci_dev()
{
    pushd /sys/bus/pci/devices/$pci_dev >/dev/null 2>&1
    ppci_dev=`ls -l physfn | cut -f 2 -d '/'`
    popd >/dev/null 2>&1
}

function __get_parent_ib_dev()
{
    ib_dev=`ls -l | awk '/'$ppci_dev'/ { print $9 }'`
}

function __get_parent_net_dev()
{
    for netdev in /sys/bus/pci/devices/$ppci_dev/net/* ; do
	if [ "$port" -eq `cat $netdev/dev_port` ]; then
	    netdev=`basename $netdev`
	    break
	fi
    done
}

function __get_vf_num()
{
    pushd /sys/bus/pci/devices/$ppci_dev >/dev/null 2>&1
    vf=`ls -l virtfn* | awk '/'$pci_dev'/ { print $9 }' | sed -e 's/virtfn//'`
    popd >/dev/null 2>&1
}

function __en_sriov_set_vf()
{
    pci_dev=$1
    shift
    [ "$1" = "port" ] && port=$2 && shift 2
    # We find our parent device by the netdev registered port number,
    # however, the netdev port numbers start at 0 while the port
    # numbers on the card start at 1, so we subtract 1 from our
    # configured port number to get the netdev number
    let port--
    # Now we need to fill in the necessary information to pass to the ip
    # command
    __get_parent_pci_dev
    __get_parent_net_dev
    __get_vf_num
    # The rest is easy.  Either the user passed valid arguments as options
    # or they didn't
    ip link set dev $netdev vf $vf $*
}

function __ib_sriov_set_vf()
{
    pci_dev=$1
    shift
    [ "$1" = "port" ] && port=$2 && shift 2
    guid=""
    __get_parent_pci_dev
    __get_parent_ib_dev
    [ -f $ib_dev/iov/$pci_dev/ports/$port/gid_idx/0 ] || return
    while [ -n "$1" ]; do
	case $1 in
	    guid)
		guid=$2
		shift 2
		;;
	    pkey)
		shift 1
		break
		;;
	    *)
		echo "Unknown option in $src"
		shift
		;;
	esac
    done
    if [ -n "$guid" ]; then
	guid_idx=`cat "$ib_dev/iov/$pci_dev/ports/$port/gid_idx/0"`
	echo "$guid" > "$ib_dev/iov/ports/$port/admin_guids/$guid_idx"
    fi
    i=0
    while [ -n "$1" ]; do
	for pkey in $ib_dev/iov/ports/$port/pkeys/*; do
	    if [ `cat $pkey` = "$1" ]; then
		echo `basename $pkey` > $ib_dev/iov/$pci_dev/ports/$port/pkey_idx/$i
		let i++
		break
	    fi
	done
	shift
    done
}

[ -d /sys/class/infiniband ] || return
pushd /sys/class/infiniband >/dev/null 2>&1

if [ -z "$*" ]; then
    src=/etc/rdma/sriov-vfs
    [ -f "$src" ] || return
    grep -v "^#" $src | while read -a args; do
	# When we use read -a to read into an array, the index starts at
	# 0, unlike below where the arg count starts at 1
	port=1
	next_arg=1
        [ "${args[$next_arg]}" = "port" ] && next_arg=3
	case ${args[$next_arg]} in
	    guid|pkey)
		__ib_sriov_set_vf ${args[*]}
		;;
	    mac|vlan|rate|spoofchk|enable)
		__en_sriov_set_vf ${args[*]}
		;;
	    *)
		;;
	esac
    done
else
    [ "$2" = "port" ] && next_arg=$4 || next_arg=$2
    case $next_arg in
	guid|pkey)
	    __ib_sriov_set_vf $*
	    ;;
	mac|vlan|rate|spoofchk|enable)
	    __en_sriov_set_vf $*
	    ;;
	*)
	    ;;
    esac
fi

popd >/dev/null 2>&1
